#include "GameLayer.h"
#include "SimpleAudioEngine.h"
#include <vector>

using namespace cocos2d;
using namespace CocosDenshion;
using namespace std;

CCScene* GameLayer::scene()
{
    // 'scene' is an autorelease object
    CCScene *scene = CCScene::create();
    
    // 'layer' is an autorelease object
    GameLayer *layer = GameLayer::create();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}

// on "init" you need to initialize your instance
bool GameLayer::init()
{
	_timeLeft = 300;
	_moveCount = 0;
	_movedIndex = -1;
	_row = 5;
	_column = 3;
	_pieceNum = _row * _column;

    //////////////////////////////
    // 1. super init first
    if ( !CCLayer::init() )
    {
        return false;
    }

    _screenSize = CCDirector::sharedDirector()->getWinSize();
    _pieceWidth = _screenSize.width / _column;
	_pieceHeight = _screenSize.height * 6 / (9 * _row);

    CCSprite * background = CCSprite::create("bg.jpg");
    CCSize imageSize = background->getContentSize();
    background->setPosition(ccp(_screenSize.width * 3 / 5, _screenSize.height * 7 / 9));
    background->setAnchorPoint(ccp(0,0));
    background->setScaleX(_screenSize.width * 2 / 5 / imageSize.width);
    background->setScaleY(_screenSize.height * 2 / 9 / imageSize.height);
    this->addChild(background);

    CCLog("width = %f, height = %f", _screenSize.width, _screenSize.height);
    CCLog("piece width = %f, piece height = %f", _pieceWidth, _pieceHeight);
    float tmp = _screenSize.height / 9 + _pieceHeight * (_row - 1);
    CCLog("pos of p0: x = 0, y = %f", tmp);

    _gameState = PLAYING;

    int i;
    char picName[9];
    GameSprite* picArray[_pieceNum];
    picArray[0] = GameSprite::gameSpriteWithFile("none.jpg");
    for(i = 1; i < _pieceNum; i++) {
    	sprintf(picName, "%d.jpeg", i);
    	CCLog("pic %d: %s", i, picName);
    	picArray[i] = GameSprite::gameSpriteWithFile(picName);
    }
    //CCLog("%s", "Done init picArray");
    _pieces = CCArray::create();
    //CCLog("%s", "Done create _pieces");
    //int tmpArray[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29};
    vector<int> numArray;//tmpArray, tmpArray + sizeof(tmpArray)/sizeof(int));
    for(i = 1; i < _pieceNum; i++) {
    	numArray.push_back(i);
    }
    //CCLog("%s", "Done init numArray");
    srand (time(NULL));
    int randIndex;
    //CCPoint pos;

	imageSize = picArray[0]->getContentSize();
	picArray[0]->setPosition(ccp(0, _screenSize.height / 9 + _pieceHeight * (_row - 1)));
	picArray[0]->setNextPosition(ccp(0, _screenSize.height / 9 + _pieceHeight * (_row - 1)));
	picArray[0]->setAnchorPoint(ccp(0,0));
	picArray[0]->setScaleX(_pieceWidth / imageSize.width);
	picArray[0]->setScaleY(_pieceHeight / imageSize.height);
	this->addChild(picArray[0]);
	_pieces->addObject(picArray[0]);
	//CCLog("%s", "Done init picArray[0]");
	CCLog("_pieceNum = %d", _pieceNum);
	int maxPiece = _pieceNum - 1;
	for(i = 1; i < _pieceNum; i++) {
		randIndex = rand() % maxPiece;
		CCLog("rand: %d, index: %d\n", randIndex, numArray[randIndex]);
		CCPoint pos = calcPosFromIndex(numArray[randIndex]);
		CCLog("pos: x = %f y = %f\n", pos.x, pos.y);
		numArray.erase(numArray.begin() + randIndex);
		imageSize = picArray[i]->getContentSize();
		picArray[i]->setPosition(pos);
		picArray[i]->setNextPosition(pos);
		picArray[i]->setAnchorPoint(ccp(0,0));
		picArray[i]->setScaleX(_pieceWidth / imageSize.width);
		picArray[i]->setScaleY(_pieceHeight / imageSize.height);
		this->addChild(picArray[i]);
		_pieces->addObject(picArray[i]);
		maxPiece--;
	}
	_pieces->retain();

	//CCLog("%s", "Done init picArray[1 .. 29]");

	// timers
	float digit_min = _timeLeft/60.0f;
	float digit_sec = ((int)_timeLeft%60);

	int min = (int)digit_min;
	int sec = (int)digit_sec;

	char str[10] = {0};
	sprintf(str, "%.2d:%.2d", min, sec);
	float timeLeftMaxWidth = _screenSize.width * 3 / 10;
	_timeLeftLabel = CCLabelTTF::create(str, "Arial", 60);
	if (_timeLeftLabel->getTexture()->getContentSize().width > timeLeftMaxWidth) {
		//float fontsize = _timeLeftLabel->getFontSize();
		_timeLeftLabel->setFontSize(60 * (timeLeftMaxWidth / _timeLeftLabel->getTexture()->getContentSize().width));
	}
	_timeLeftLabel->setPosition(ccp(_screenSize.width / 20, _screenSize.height * 43 / 54));
	_timeLeftLabel->setAnchorPoint(ccp(0,0));

	//scheduleUpdate();
	//schedule(schedule_selector(GameLayer::tick));

	addChild(_timeLeftLabel);

	// move count
	sprintf(str, "%d", _moveCount);
	float moveCountMaxWidth = _screenSize.width * 3 / 10;
	_moveCountLabel = CCLabelTTF::create(str, "Arial", 60);
	if (_moveCountLabel->getTexture()->getContentSize().width > moveCountMaxWidth) {
		_moveCountLabel->setFontSize(60 * (moveCountMaxWidth / _moveCountLabel->getTexture()->getContentSize().width));
	}
	_moveCountLabel->setPosition(ccp(_screenSize.width * 7 / 20, _screenSize.height * 43 / 54));
	_moveCountLabel->setAnchorPoint(ccp(0,0));
	this->addChild(_moveCountLabel);

    //listen for touches
    this->setTouchEnabled(true);
    
    //create main loop
    this->schedule(schedule_selector(GameLayer::update));
    return true;
}

/*void GameLayer::tick(float dt)
{
	if(_timeLeft > dt) {
		_timeLeft -=dt;

		float digit_min = _timeLeft/60.0f;
		float digit_sec = ((int)_timeLeft%60);

		int min = (int)digit_min;
		int sec = (int)digit_sec;

		char str[10] = {0};
		sprintf(str, "%.2d:%.2d", min, sec);
		_timeLeftLabel->setString( str );
	}
}*/


void GameLayer::setPieceNum(int num)
{
	_pieceNum = num;
}

void GameLayer::ccTouchesBegan(CCSet* pTouches, CCEvent* event) {
	CCSetIterator i;
	CCTouch* touch;
	CCPoint tap;
	GameSprite * piece;
	for( i = pTouches->begin(); i != pTouches->end(); i++) {
		touch = (CCTouch*) (*i);
		if(touch) {
			tap = touch->getLocation();
			for (int p = 0; p < _pieces->count(); p++) {
				piece = (GameSprite *) _pieces->objectAtIndex(p);
				if (piece->boundingBox().containsPoint(tap)) {
					piece->setTouch(touch);
					CCLog("touch index = %d", p);
				}
			}
		}
	}
}

void GameLayer::ccTouchesMoved(CCSet* pTouches, CCEvent* event) {
	CCSetIterator i;
	CCTouch* touch;
	CCPoint tap;
	GameSprite * piece;
	GameSprite * piece_0 = (GameSprite *) _pieces->objectAtIndex(0);
	for( i = pTouches->begin(); i != pTouches->end(); i++) {
		touch = (CCTouch*) (*i);
		if(touch) {
			tap = touch->getLocation();
			for (int p = 1; p < _pieces->count(); p++) {
				piece = (GameSprite *) _pieces->objectAtIndex(p);
				if (piece->getTouch() != NULL && piece->getTouch() == touch) {
					CCPoint nextPosition = tap;
					CCPoint curPosition = piece->getPosition();

					int nextIndex = calcIndexFromPos(nextPosition);
					int curIndex = calcIndexFromPos(ccp(curPosition.x + 0.5, curPosition.y + 0.5));
					int piece0Index = calcIndexFromPos(ccp(piece_0->getPosition().x + 0.5, piece_0->getPosition().y + 0.5));
					CCLog("curIndex = %d, nextIndex = %d, piece0Index = %d", curIndex, nextIndex, piece0Index);
					if(nextIndex == piece0Index && isAdjacent(curIndex, nextIndex)) {
						piece->setNextPosition(calcPosFromIndex(nextIndex));
						piece_0->setNextPosition(calcPosFromIndex(curIndex));
						_movedIndex = p;
						CCLog("movedIndex = %d", p);
					}
				}
			}
		}
	}
}

void GameLayer::ccTouchesEnded(CCSet* pTouches, CCEvent* event) {
	CCSetIterator i;
	CCTouch* touch;
	CCPoint tap;
	GameSprite * piece;
	for( i = pTouches->begin(); i != pTouches->end(); i++) {
		touch = (CCTouch*) (*i);
		if(touch) {
			tap = touch->getLocation();
			for (int p = 0; p < _pieces->count(); p++) {
				piece = (GameSprite *) _pieces->objectAtIndex(p);
				if (piece->getTouch() != NULL && piece->getTouch() == touch) {
					piece->setTouch(NULL);
					//piece->setVector(ccp(0,0));
				}
			}
		}
	}
}

void GameLayer::update (float dt) {
	GameSprite * piece;
	/*for (int p = 0; p < _pieces->count(); p++) {
		piece = (GameSprite *) _pieces->objectAtIndex(p);
		int curIndex = calcIndexFromPos(piece->getPosition());
		int nextIndex = calcIndexFromPos(piece->getNextPosition());
		if(curIndex != nextIndex) {
			piece->setPosition(piece->getNextPosition());
		}
	}*/
	if(_timeLeft > dt) {
		_timeLeft -=dt;

		float digit_min = _timeLeft/60.0f;
		float digit_sec = ((int)_timeLeft%60);

		int min = (int)digit_min;
		int sec = (int)digit_sec;

		char str[10] = {0};
		sprintf(str, "%.2d:%.2d", min, sec);
		_timeLeftLabel->setString( str );
	}
	if(_movedIndex >= 0) {
		piece = (GameSprite *) _pieces->objectAtIndex(_movedIndex);
		piece->setPosition(piece->getNextPosition());
		piece = (GameSprite *) _pieces->objectAtIndex(0);
		piece->setPosition(piece->getNextPosition());
		_movedIndex = -1;

		// update move count
		_moveCount++;
		CCString* cstr = CCString::createWithFormat("%d", _moveCount);
		_moveCountLabel->setString(cstr->getCString ());

		if(_gameState != WIN && isWin()) {
			_gameState = WIN;
			CCLOG("%s\n", "WIN!!!");
		}
	}
}

int GameLayer::calcIndexFromPos(CCPoint pos)
{
	for(int j = 1; j <= _column; j++) {
		if(pos.x < j * _pieceWidth) {
			for(int i = 1; i <= _row; i++) {
				if(pos.y > (_row - i) * _pieceHeight + (_screenSize.height / 9) &&
				   pos.y <= (_row - i + 1) * _pieceHeight + (_screenSize.height / 9)) {
					return _column * (i - 1) + (j - 1);
				}
			}
		}
	}
	return -1;
}

CCPoint GameLayer::calcPosFromIndex(int index) // bottom left
{
	CCPoint pos;
	pos.x = (index % _column) * (_screenSize.width / _column);
	//pos.y = (1 + (6 / _row) * (_column - ((int)(index / _column)))) * (_screenSize.height / 9);
	pos.y = (_row - ((int)(index / _column)) - 1) * _pieceHeight + (_screenSize.height / 9);
	return pos;
}

bool GameLayer::isWin()
{
	GameSprite * piece;
	for (int p = 0; p < _pieces->count(); p++) {
		piece = (GameSprite *) _pieces->objectAtIndex(p);
		int curIndex = calcIndexFromPos(ccp(piece->getPosition().x + 0.5, piece->getPosition().y + 0.5));
		if(curIndex != p) {
			return false;
		}
	}
	return true;
}

bool GameLayer::isAdjacent(int index1, int index2)
{
	if(index1 == index2 + _column || index1 == index2 - _column) {
		return true;
	}
	if((index1 == index2 + 1 && index1 % _column != 0) || (index1 == index2 - 1 && index2 % _column != 0)) {
		return true;
	}
	return false;
}

GameLayer::~GameLayer() {
	CC_SAFE_RELEASE(_pieces);
}
